package com.life.xxx.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class JwtUtil {

    // 访问令牌基础密钥，用于生成最终密钥
    private static final String ACCESS_TOKEN_SECRET = "lifeStatusKssAndLink";

    // 刷新令牌基础密钥，用于生成最终密钥
    private static final String REFRESH_TOKEN_SECRET = "F1qo8d7v+9t3Y6x2W5z8V1b9X3c7Y5n2K8p4L7o9M2n5Q8r1T6w4E9y7U1i5O3s7V5a8D2f6G9j4H7k1N3m6P5t8W2q5R7u9";

    // 访问令牌过期时间：2小时（单位：毫秒）
    private static final long ACCESS_TOKEN_EXPIRATION = 7200000;

    // 刷新令牌过期时间：7天（单位：毫秒）
    private static final long REFRESH_TOKEN_EXPIRATION = 604800000;

    /**
     * 根据访问基础密钥、用户的密码哈希和盐生成最终的JWT签名密钥
     * @param passwordHash 用户密码的哈希值
     * @param salt 用户的盐值
     * @param secret 基础密钥
     * @return 用于JWT签名的最终密钥 (SHA-256哈希后的十六进制字符串)
     */
    public static String generateFinalSecret(String passwordHash, String salt) throws NoSuchAlgorithmException {
        // 将基础密钥、密码哈希和盐拼接
        String combinedSecret = ACCESS_TOKEN_SECRET  + passwordHash + salt;

        // 使用SHA-256进行哈希
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(combinedSecret.getBytes());

        // 将字节数组转换为十六进制字符串
        StringBuilder hexString = new StringBuilder();
        for (byte b : hashBytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }
        System.out.println(hexString.toString());
        return hexString.toString();
    }


    /**
     * 生成访问令牌
     * @param passwordHash 用户密码的哈希值
     * @param salt 用户的盐值
     * @param userId 用户ID
     * @return JWT访问令牌
     */
    public static String generateAccessToken(String passwordHash,String salt,String userId) throws Exception {
        Date now = new Date();
        String finalSecret = generateFinalSecret(passwordHash,salt);
        return Jwts.builder()
                .setSubject(userId)
                .setIssuedAt(now)
                .setExpiration(new Date(now.getTime() + ACCESS_TOKEN_EXPIRATION))
                .signWith(SignatureAlgorithm.HS256, finalSecret)
                .compact();
    }

    /**
     * 生成刷新令牌
     * @param userId 用户ID
     * @return JWT刷新令牌
     */
    public static String generateRefreshToken(String userId) {
        return Jwts.builder()
                .setSubject(userId)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + REFRESH_TOKEN_EXPIRATION))
                .signWith(SignatureAlgorithm.HS256, REFRESH_TOKEN_SECRET)
                .compact();
    }

    /**
     * 验证访问令牌
     * @param passwordHash 用户密码的哈希值
     * @param salt 用户的盐值
     * @param token 令牌
     * @return 如果验证通过返回true，否则返回false
     */
    public static boolean validateAccessToken(String passwordHash, String salt,String token) {
        try {
            String finalSecret = generateFinalSecret(passwordHash,salt);
            Jwts.parser().setSigningKey(finalSecret).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 验证刷新令牌
     * @param token 令牌
     * @param userId 用户ID
     * @return String
     */
    public static String validateRefreshToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(REFRESH_TOKEN_SECRET)
                    .parseClaimsJws(token)
                    .getBody()
                    .getSubject();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 从令牌中提取用户ID
     * @param token 令牌
     * @return 用户ID
     */
    public static String getUserIdFromRefreshToken(String token) {
        if (token == null || token.isEmpty()) {
            return null;
        }

        try {
            // 1. 按 '.' 分割 JWT
            String[] parts = token.split("\\.");
            if (parts.length != 3) {
                return null; // 不是标准的 JWT 格式
            }

            // 2. Base64Url 解码 payload
            String payload = parts[1];
            byte[] decodedBytes = Base64.getUrlDecoder().decode(payload);
            String payloadJson = new String(decodedBytes, StandardCharsets.UTF_8);

            // 3. 解析 JSON，提取 "sub" 字段
            // 方式一：用 Jackson（推荐）
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(payloadJson);
            return node.has("sub") ? node.get("sub").asText() : null;

        } catch (Exception e) {
            return null; // 格式错误、解码失败等
        }
    }

    /**
     * 检查 Token 是否需要刷新（剩余时间 < 5分钟）
     * @param token JWT 令牌
     * @return true 表示需要刷新
     */
    public static boolean shouldRefresh(String token) {
        try {
            // 先提取 payload（不验证签名也能提取）
            String[] parts = token.split("\\.");
            if (parts.length != 3) return false;

            // Base64Url 解码 payload
            byte[] decoded = Base64.getUrlDecoder().decode(parts[1]);
            String json = new String(decoded, StandardCharsets.UTF_8);

            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(json);
            long exp = node.get("exp").asLong(); // 过期时间（秒）

            // 当前时间（毫秒转秒）
            long currentTime = System.currentTimeMillis() / 1000;

            // 剩余时间小于 5 分钟（300秒）就需要刷新
            return (exp - currentTime) < 300;
        } catch (Exception e) {
            return false;
        }
    }
}
